package org.hk.kg.ui;

import java.awt.event.ContainerEvent;
import java.awt.event.ContainerListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.imageio.ImageIO;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JEditorPane;
import javax.swing.JToggleButton.ToggleButtonModel;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import javax.swing.event.UndoableEditEvent;
import javax.swing.event.UndoableEditListener;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.Element;
import javax.swing.text.PlainDocument;
import javax.swing.text.StyleConstants;
import javax.swing.text.html.HTML;
import javax.swing.text.html.HTML.Tag;
import javax.swing.text.html.HTMLDocument;
import javax.swing.text.html.HTMLDocument.Iterator;
import javax.swing.text.html.Option;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hk.kg.TraceObject;
import org.hk.kg.exception.EleParserException;
import org.hk.kg.utils.Constants;
import org.hk.kg.utils.LocalResouce;
import org.hk.kg.utils.StringUtils;
import org.hk.kg.web.BaseAction;

public class KGBrowserFrame extends JEditorPane implements IHTMLDisplayer,HyperlinkListener{
	private static final long serialVersionUID = -1328322577102054853L;
	private static Log logger = LogFactory.getLog(KGBrowserFrame.class);
	private BaseAction currentAction;
	private static Pattern METHOD_PARAM_PATTERN = Pattern.compile("([^=]*)=([^=]*)");
	public static class FileCharge implements UndoableEditListener
	{
		private String reg;
		public FileCharge(String reg)
		{
			this.reg = reg;
		}
		public void undoableEditHappened(UndoableEditEvent e) {
			PlainDocument doc = (PlainDocument) e.getSource();
			try {
				String txt = doc.getText(0, doc.getLength());
				if(StringUtils.isEmpty(txt))
				{
					return;
				}
				if(!txt.matches(reg))
				{
					e.getEdit().undo();
					return;
				}
				File img = new File(txt);
				if(!img.exists() || img.isDirectory())
				{
					e.getEdit().undo();
					return;
				}
			} catch (BadLocationException e1) {
				e.getEdit().undo();
			}
		}
	}
	private static class File2Show implements DocumentListener {
		private JEditorPane parent;
		private String targetImg;
		private File2Show(JEditorPane parent,String targetImg)
		{
			this.parent = parent;
			this.targetImg = targetImg;
		}
		private void show2Displayer(DocumentEvent arg0)
		{
			HTMLDocument doc = (HTMLDocument) parent.getDocument();
			Element element = doc.getElement(targetImg);
			try {
				String entered = arg0.getDocument().getText(arg0.getOffset(), arg0.getLength());
				if(!(entered.endsWith(".jpg")||entered.endsWith(".JPG")||StringUtils.isEmpty(entered)))
				{
					doc.setInnerHTML(element, "");
					return;
				}
				
				String txt = arg0.getDocument().getText(0, arg0.getDocument().getLength());
				if(StringUtils.isEmpty(targetImg))
				{
					return;
				}
				if(txt.endsWith(".jpg")||txt.endsWith(".JPG"))
				{
					AttributeSet attr = element.getAttributes();
					String height = (String) attr.getAttribute(HTML.Attribute.HEIGHT),
						width= (String) attr.getAttribute(HTML.Attribute.WIDTH);
					//转图片大小,写入临时目录
					doc.setInnerHTML(
							element,
							"<img src=\"file:/" + LocalResouce.getTempImage(txt, width, height) + "\"/>");
				}
				else
				{
					doc.setInnerHTML(element, "");
				}
			} catch (BadLocationException e) {
				try {
					doc.setInnerHTML(element, "");
				} catch (BadLocationException e1) {
				} catch (IOException e1) {
				}
			} catch (IOException e) {
				logger.error(e);
			}
		}
		public void removeUpdate(DocumentEvent arg0) {
			show2Displayer(arg0);
		}
		
		public void insertUpdate(DocumentEvent arg0) {
			show2Displayer(arg0);
		}
		
		public void changedUpdate(DocumentEvent arg0) {
			show2Displayer(arg0);
		}
		
		
	};
	
	public KGBrowserFrame()
	{
		//重要,否则无法获取到input/textarea等的输入内容
		this.setEditable(false);
		this.addHyperlinkListener(this);
		final JEditorPane root = this;
		this.addContainerListener(new ContainerListener() {
			private HTMLDocument doc;
			public void componentRemoved(ContainerEvent arg0) {}
			
			public void componentAdded(ContainerEvent arg0) {
				HTMLDocument currentDoc = (HTMLDocument) getDocument();
				if(!currentDoc.equals(doc))
				{
					doc = currentDoc;
					Iterator iterator = doc.getIterator(Tag.INPUT);
					while(iterator.isValid())
					{
						AttributeSet attrSet = iterator.getAttributes();
						Object modelObj = attrSet.getAttribute(StyleConstants.ModelAttribute);
						if(modelObj instanceof PlainDocument)
						{
							if(attrSet.getAttribute(HTML.Attribute.TYPE).equals("file"))
							{
								PlainDocument pDoc = (PlainDocument) modelObj;
								String targetImg = (String) attrSet.getAttribute(HTML.Attribute.TARGET);
								//pDoc.addUndoableEditListener(new FileCharge("^.*[.](jpg|JPG)"));
								pDoc.addDocumentListener(new File2Show(root,targetImg));
							}
						}
						iterator.next();
					}
				}
			}
		});
	}
	
	public void display(URL url,BaseAction action) {
		try {
			this.setPage(url);
			currentAction = action;
		} catch (IOException e) {
			logger.error(e);
		}
	}
	
	public void display(String content, String target, BaseAction action) {
		HTMLDocument doc = (HTMLDocument) this.getDocument();
		Element element = doc.getElement(target);
		if(null != element)
		{
			try {
				doc.setInnerHTML(element, content);
			} catch (BadLocationException e) {
				logger.error("display content fail:BadLocationException",e);
			} catch (IOException e) {
				logger.error("display content fail:IOException",e);
			}
		}
	}
	
	private void buildInputParams(Iterator iterator,ParamsStack params)
	{
		while(iterator.isValid())
		{
			AttributeSet attrSet = iterator.getAttributes();
			Object modelObj = attrSet.getAttribute(StyleConstants.ModelAttribute);
			if(modelObj instanceof PlainDocument)
			{
				PlainDocument pDoc = (PlainDocument) modelObj;
				try {
					String inputName = (String) attrSet.getAttribute(HTML.Attribute.NAME);
					String inputValue = pDoc.getText(0, pDoc.getLength());
					params.add(inputName, inputValue);
				} catch (BadLocationException e) {
					// TODO Auto-generated catch block
					logger.error(e);
				}
			}
			else if(modelObj instanceof ToggleButtonModel)
			{
				ToggleButtonModel toggleBtn = (ToggleButtonModel) modelObj;
				String inputName =  (String) attrSet.getAttribute(HTML.Attribute.NAME);
				if(toggleBtn.isSelected())
				{
					String inputValue = (String) attrSet.getAttribute(HTML.Attribute.VALUE);
					params.add(inputName, inputValue);
				}
				else
				{
					params.add(inputName, "");
				}
			}
			else
			{
				String inputName =  (String) attrSet.getAttribute(HTML.Attribute.NAME);
				String inputValue = (String) attrSet.getAttribute(HTML.Attribute.VALUE);
				params.add(inputName, inputValue);
			}
			iterator.next();
		}
	}
	
	private void buildSelectParams(Iterator iterator,ParamsStack params)
	{
		while(iterator.isValid())
		{
			AttributeSet attrSet = iterator.getAttributes();
			Object modelObj = attrSet.getAttribute(StyleConstants.ModelAttribute);
			DefaultComboBoxModel combox = (DefaultComboBoxModel) modelObj;
			Option selected = (Option) combox.getSelectedItem();
			String inputName =  (String) attrSet.getAttribute(HTML.Attribute.NAME);
			String inputValue = selected.getValue();
			params.add(inputName, inputValue);
			iterator.next();
		}
	}
	/**
	 * 链接点击
	 */
	public void hyperlinkUpdate(HyperlinkEvent arg0) {
		if(HyperlinkEvent.EventType.ACTIVATED == arg0.getEventType())
		{
			ParamsStack params = new ParamsStack();
			HTMLDocument doc = (HTMLDocument) this.getDocument();
			//将input中的内容写入到params中
			buildInputParams(doc.getIterator(Tag.INPUT),params);
			//将textarea中的内容写入到params中
			buildInputParams(doc.getIterator(Tag.TEXTAREA), params);
			buildSelectParams(doc.getIterator(Tag.SELECT),params);
			
			//获取按钮的点击内容
			String methodPart = arg0.getURL().toString().replaceAll(".*[#]", "");
			String method = methodPart.replaceAll("\\?.*", "");
			String displayTarget = null;
			
			if(methodPart.matches("^.*[?]{1}.*$"))
			{
				displayTarget = methodPart.replaceAll(".*\\?", "");
			}
			if(!StringUtils.isEmpty(displayTarget))
			{
				Matcher matcher = METHOD_PARAM_PATTERN.matcher(displayTarget);
				while(matcher.find())
				{
					String paramKey = matcher.group(1),
						paramsValue = matcher.group(2);
					logger.debug("Request with:" + paramKey + "," + paramsValue);
					params.add(paramKey, paramsValue);
				}
			}
			if(currentAction!=null)
			{
				TraceObject trace = null;
				try {
					Object rlt = currentAction.invoke(method, params);
					if(rlt instanceof String)
					{
						if(rlt.equals(BaseAction.None))
						{
							return;
						}
						trace = new TraceObject(rlt.toString(),true);
					}
					else if(rlt instanceof TraceObject)
					{
						trace = (TraceObject) rlt;
						if(trace.getCommandId().equals(BaseAction.None))
						{
							return;
						}
					}
					if(!StringUtils.isEmpty(displayTarget))
					{
						Matcher matcher = METHOD_PARAM_PATTERN.matcher(displayTarget);
						while(matcher.find())
						{
							String paramKey = matcher.group(1),
								paramsValue = matcher.group(2);
							trace.addParam(paramKey, paramsValue);
						}
					}
					KGUiContext.instance.action(trace);
				} catch (EleParserException e) {
					logger.error(e);
				}
			}
		}
	}
}
